/**
 *  This file is part of PennerBot
 *
 *  Copyright (C) 2010 microkernel
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iomanip>
#include <sstream>

#include <wx/icon.h>
#include <wx/image.h>
#include <wx/mstream.h>

#include <core/anticaptcha.hpp>
#include <core/config.hpp>
#include <core/configparser.hpp>
#include <core/portable.hpp>
#include <core/strings.hpp>
#include <core/version.hpp>

#include <gui/mainframe.hpp>
#include <gui/statuslistener.hpp>
#include <gui/settingsdialog.hpp>

#include <gui/donatebutton.h>
#include <gui/icon.h>
#include <gui/tray_icon.h>

namespace PBot
{
namespace GUI
{

DECLARE_EVENT_TYPE(wxEVT_ADD_STATUS_MESSAGE, -1)
DEFINE_EVENT_TYPE(wxEVT_ADD_STATUS_MESSAGE)

DECLARE_EVENT_TYPE(wxEVT_UNSAFE_MESSAGE, -1)
DEFINE_EVENT_TYPE(wxEVT_UNSAFE_MESSAGE)

BEGIN_EVENT_TABLE(MainFrame, FrmPBot)
  EVT_COMMAND  (-1, wxEVT_ADD_STATUS_MESSAGE, MainFrame::SafeAddStatusMessage)
  EVT_COMMAND  (-1, wxEVT_UNSAFE_MESSAGE, MainFrame::UnsafeMessageBox)
  EVT_TIMER(1337, MainFrame::OnTimer)
END_EVENT_TABLE();

MainFrame::MainFrame(Core::Config* _cfg)
 : FrmPBot(NULL), listener(StatusListener::GetInstance()), cfg(_cfg), bot(NULL), updateCheck(NULL), running(true), timer(this, 1337), trayIcon(this), BCtime(0), BCcollecting(false)
{
    listener.SetFrame(this);
    listener.StartListener();

    updateCheck = new Core::UpdateCheck(1);
    bot = new Core::Bot(cfg);

    thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MainFrame::ThreadDo, this)));

    tctrlUsername->SetValue(wxString(cfg->username.c_str(), wxConvUTF8));

    switch(cfg->game)
    {
        case Core::Config::PENNERGAME_H:
            tctrlGame->SetValue(wxT("Pennergame (Hamburg)"));
            break;

        case Core::Config::PENNERGAME_B:
            tctrlGame->SetValue(wxT("Pennergame (Berlin)"));
            break;

        case Core::Config::PENNERGAME_M:
            tctrlGame->SetValue(wxT("Pennergame (Munich)"));
            break;

        case Core::Config::DOSSERGAME:
            tctrlGame->SetValue(wxT("Dossergame"));
            break;

        case Core::Config::MENELGAME_W:
            tctrlGame->SetValue(wxT("Menelgame (Warsaw)"));
            break;

        case Core::Config::MENELGAME_K:
            tctrlGame->SetValue(wxT("Menelgame (Krakow)"));
            break;

        case Core::Config::CLODOGAME_P:
            tctrlGame->SetValue(wxT("Clodogame (Paris)"));
            break;

        case Core::Config::CLODOGAME_M:
            tctrlGame->SetValue(wxT("Clodogame (Marseille)"));
            break;

        case Core::Config::MENDIGOGAME:
            tctrlGame->SetValue(wxT("Mendigogame"));
            break;

        case Core::Config::SERSERIONLINE:
            tctrlGame->SetValue(wxT("Serserionline"));
            break;

        case Core::Config::BUMRISE:
            tctrlGame->SetValue(wxT("Bumrise"));
            break;

        case Core::Config::FAVELADOGAME:
            tctrlGame->SetValue(wxT("Faveladogame"));
            break;
    }

    timer.Start(100);

    wxMemoryInputStream istream(donateButton, size_donateButton);
    wxBitmap btmDonateButton = wxImage(istream, wxBITMAP_TYPE_PNG, -1);

    btnDonate->SetBitmapLabel(btmDonateButton);

    // Tray icon
    wxMemoryInputStream traystream(tray_icon, size_tray_icon);
    wxIcon icoTrayIcon;
    icoTrayIcon.CopyFromBitmap(wxImage(traystream, wxBITMAP_TYPE_ICO, -1));

    trayIcon.SetIcon(icoTrayIcon, wxT("PennerBot - ") + tctrlUsername->GetValue() + wxT(" - ") + tctrlGame->GetValue());

    // Main icon
    wxMemoryInputStream iconstream(icon, size_icon);
    wxIcon icoIcon;
    icoIcon.CopyFromBitmap(wxImage(iconstream, wxBITMAP_TYPE_ICO, -1));
    SetIcon(icoIcon);

    SetTitle(wxT("PennerBot ") + wxString(__PBOT_GUI_VERSION__, wxConvUTF8) + wxT(" by microkernel"));
}

MainFrame::~MainFrame()
{
    bot->Stop();

    thread->join();

    listener.RequestStop();

    listener.Destroy();
    Core::AntiCaptcha::GetInstance().Destroy();
    Core::Strings::GetInstance().Destroy();

    delete bot;
    delete updateCheck;
}

void MainFrame::AddStatusMessage(const std::string& msg)
{
    wxCommandEvent event(wxEVT_ADD_STATUS_MESSAGE);
    event.SetString(wxString(std::string(msg + "\n").c_str(), wxConvUTF8));
    GetEventHandler()->AddPendingEvent(event);
}

void MainFrame::SafeAddStatusMessage(wxCommandEvent& event)
{
    time_t rawtime;
    tm* timeinfo;

    time(&rawtime);

    int hour, minute, seconds;
    timeinfo = localtime(&rawtime);

    hour = timeinfo->tm_hour;
    minute = timeinfo->tm_min;
    seconds = timeinfo->tm_sec;

    std::stringstream formatString;
    formatString << "[" << std::setw(2) << std::setfill('0') << hour << ":" << std::setw(2) << std::setfill('0') << minute << ":" << std::setw(2) << std::setfill('0') << seconds << "] ";

    tctrlStatus->AppendText(wxString(formatString.str().c_str(), wxConvUTF8) + event.GetString());
}

void MainFrame::ThreadDo()
{
    while(bot->IsActive())
    {
        if(updateCheck->GetVersionStatus() == Core::UpdateCheck::UNSAFE)
        {
            bot->Stop();
            wxCommandEvent event(wxEVT_UNSAFE_MESSAGE);
            GetEventHandler()->AddPendingEvent(event);
            break;
        }

        bot->Do();
        PortableMicroSleep(100);
    }
}

void MainFrame::OnTimer(wxTimerEvent& event)
{
    if(BCcollecting)
    {
        ++count;
        if(count % 10 == 0)
        {
            stxtStatusInfo->SetLabel(BCstatusText + wxString::Format(_T(" (%ds)"), BCtime));
            prgBar->SetValue(100-100*BCtime/BCfullTime);
            --BCtime;

            if(BCtime > 0)
            {
                return;
            }
            else
            {
                BCstatusText = wxT("Waiting...");
                BCcollecting = false;
            }
        }

        return;
    }

    if(BCtime > 0)
    {
        BCcollecting = true;
        count = 0;

        BCfullTime = BCtime;
    }
    else
    {
        BCcollecting = false;
        stxtStatusInfo->SetLabel(BCstatusText);
    }

}

void MainFrame::OnClose(wxCloseEvent& event)
{
    trayIcon.RemoveIcon();
    event.Skip();
}

void MainFrame::OnIconize(wxIconizeEvent& event)
{
    Show(!event.Iconized());
    event.Skip();
}

void MainFrame::OnBtnAbout(wxCommandEvent& event)
{
    DlgAbout dlg(this);
    dlg.ShowModal();
}

void MainFrame::OnBtnDonate(wxCommandEvent& event)
{
    wxLaunchDefaultBrowser(wxT("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=53060"));
}

void MainFrame::OnBtnSettings(wxCommandEvent& event)
{
    SettingsDialog dlg(cfg);

    bool correctData = false;
    bool reconnect = false;

    while(!correctData)
    {
        if(dlg.ShowModal() == wxID_OK)
        {
            if(!dlg.GetUsername())
            {
                wxMessageBox(wxT("Missing username"), wxT("PennerBot"), wxICON_ERROR);
                continue;
            }
            else
            {
                std::string newusername(dlg.GetUsername().mb_str(wxConvUTF8));
                if(newusername != cfg->username)
                {
                    reconnect = true;
                }
                cfg->username = newusername;
            }

            if(!dlg.GetPassword())
            {
                wxMessageBox(wxT("Missing password"), wxT("PennerBot"), wxICON_ERROR);
                continue;
            }
            else
            {
                std::string newpassword(dlg.GetPassword().mb_str(wxConvUTF8));
                if(newpassword != cfg->password)
                {
                    reconnect = true;
                }
                cfg->password = newpassword;
            }

            if(!dlg.GetUserAgent())
            {
                wxMessageBox(wxT("Missing User-Agent"), wxT("PennerBot"), wxICON_ERROR);
                continue;
            }
            else
            {
                std::string newUserAgent(dlg.GetUserAgent().mb_str(wxConvUTF8));
                if(newUserAgent != cfg->userAgent)
                {
                    reconnect = true;
                }
                cfg->userAgent = newUserAgent;
            }

            Core::Config::Games newgame = dlg.GetGame();
            if(newgame != cfg->game)
            {
                reconnect = true;
            }
            cfg->game = newgame;

            std::string newproxy(dlg.GetProxy().mb_str(wxConvUTF8));
            if(newproxy != cfg->proxy)
            {
                reconnect = true;
            }
            cfg->proxy = newproxy;


            cfg->BC_enabled = dlg.GetBCEnabled();

            if(dlg.GetBCMinWait() > dlg.GetBCMaxWait())
            {
                wxMessageBox(wxT("Minimal wait time must be lower than maximal wait time"), wxT("PennerBot"), wxICON_ERROR);
                continue;
            }

            cfg->BC_minwait = dlg.GetBCMinWait();
            cfg->BC_maxwait = dlg.GetBCMaxWait();
            cfg->BC_thirtyminprobability = dlg.GetBCThirtyMin();
            cfg->BC_usejunk = dlg.GetBCUseJunk();

            PBot::Core::ConfigParser parser;
            parser.SaveToFile("config.xml", cfg);
            correctData = true;
        }
        else
        {
            break;
        }
    }

    if(reconnect == true)
    {
       //TODO restart
       wxMessageBox(wxT("You have to restart the bot because you changed some important values."), wxT("PennerBot"), wxICON_INFORMATION);
       Close(true);
    }
}

void MainFrame::OnBtnWebsite(wxCommandEvent& event)
{
    wxLaunchDefaultBrowser(wxT("http://pb.kicks-ass.org"));
}

void MainFrame::UnsafeMessageBox(wxCommandEvent& event)
{
    wxMessageBox(wxT("This version of PennerBot is not safe anymore\nLook at http://pb.kicks-ass.org for new versions"), wxT("PennerBot"), wxICON_INFORMATION);
}

BEGIN_EVENT_TABLE(MainFrame::TrayIcon, wxTaskBarIcon)
    EVT_MENU(0, MainFrame::TrayIcon::MenuQuit)
    EVT_TASKBAR_LEFT_UP(MainFrame::TrayIcon::OnTrayIconLeftUp)
END_EVENT_TABLE()

MainFrame::TrayIcon::TrayIcon(MainFrame *_parent)
 : parent(_parent)
{
}

MainFrame::TrayIcon::~TrayIcon()
{
}

wxMenu*  MainFrame::TrayIcon::CreatePopupMenu()
{
    wxMenu *trayMenu = new wxMenu;

    trayMenu->Append(0, wxT("E&xit"), wxT(""), wxITEM_NORMAL);

    return trayMenu;
}

void MainFrame::TrayIcon::MenuQuit(wxCommandEvent& _event)
{
    parent->Close(true);
}

void MainFrame::TrayIcon::OnTrayIconLeftUp(wxTaskBarIconEvent& event)
{
    parent->Iconize(!parent->IsIconized());

    if(!parent->IsShown())
    {
        parent->Show(true);
        parent->Raise();
    }
    else
    {
        parent->Show(false);
    }
}

}
}
